﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;
using ProgNetComponents.Design.TypeConverters;
using ProgNetComponents.Design.Attributes;
using System.Windows.Forms;
using ProgNetComponents;
using ProgNetComponentsDx.Browsers.Design.Editors;
using System.Data;
using ProgNetComponents.Classes;
using ProgNetComponents.Interfaces;
using ProgNetComponentsDx.Browsers.Design;
using ProgNetComponentsDx.Enums;
using ProgNetComponents.Controls;
using ProgNetComponents.Design.Designers;
using System.Drawing.Design;

namespace ProgNetComponentsDx.Browsers
{
    [TypeConverter(typeof(BrowserTypeConverter))]
    public class Browser :  BaseCustomObject, ICloneable, INamedObject
    {
        private BrowserForm form = null;
        private BrowserForm Form
        {
            get
            {
                if(form == null)
                    form = new BrowserForm();
                return form;
            }
        }
        
        #region static
        private static bool _UseFilter =true;
        public static bool UseFilter
        {
            get { return _UseFilter; }
            set { _UseFilter = value; }
        }
        #endregion

        #region Fields
        private BrowserColumnCollection _Columns;
        private string _Name;
        #endregion

        public Browser() { }
        public Browser(
            string Name,
            string Caption,
            string[] Tables,
            string ValueMember,
            string DisplayMember,
            BrowserDisplayType DisplayType,
            BrowserColumn[] columns)
            : this(Name, Caption, Tables, ValueMember, DisplayMember, DisplayType, BrowserConfigDisplayType.Auto, null, null, columns)
        {
            DefaultConfigDisplayType = DisplayType.AsEnum<BrowserConfigDisplayType>(BrowserConfigDisplayType.DropDown);
        }

        public Browser(
            string Name, 
            string Caption, 
            string[] Tables, 
            string ValueMember, 
            string DisplayMember, 
            BrowserDisplayType DisplayType, 
            BrowserConfigDisplayType DefaultConfigDisplayType, 
            string Group, 
            string Filter, 
            BrowserColumn[] columns,
            string customColumnQuery,
            string customFromQuery,
            string customFilterQuery)
        {
            this.Name = Name;
            this.Caption = Caption;
            this.Tables = Tables;
            this.ValueMember = ValueMember;
            this.DisplayMember = DisplayMember;
            this.DisplayType = DisplayType;
            this.DefaultConfigDisplayType = DefaultConfigDisplayType;
            this.Group = Group;
            this.IsStatic = false;
            this.Filter = Filter;
            RefreshOnPopup = false;
            if (columns != null)
                Columns.AddRange(columns);
            this.CustomColumnQuery = customColumnQuery;
            this.CustomFilterQuery = customFilterQuery;
            this.CustomFromQuery = customFromQuery;
        }

        public Browser(
           string Name,
           string Caption,
           string[] Tables,
           string ValueMember,
           string DisplayMember,
           BrowserDisplayType DisplayType,
           BrowserConfigDisplayType DefaultConfigDisplayType,
           string Group,
           string Filter,
           BrowserColumn[] columns)
        {
            this.Name = Name;
            this.Caption = Caption;
            this.Tables = Tables;
            this.ValueMember = ValueMember;
            this.DisplayMember = DisplayMember;
            this.DisplayType = DisplayType;
            this.DefaultConfigDisplayType = DefaultConfigDisplayType;
            this.Group = Group;
            this.IsStatic = false;
            this.Filter = Filter;
            RefreshOnPopup = false;
            if (columns != null)
                Columns.AddRange(columns);
        }

        public Browser(string Name, string Caption, string ValueMember, string DisplayMember,
            BrowserDisplayType DisplayType, BrowserConfigDisplayType DefaultConfigDisplayType, string Group, string Filter, BrowserColumn[] columns, bool refreshOnPopUp)
            : this(Name, Caption, null, ValueMember, DisplayMember, DisplayType, DefaultConfigDisplayType, Group, Filter, columns)
        {
            RefreshOnPopup = refreshOnPopUp;
            IsStatic = true;
        }
        
        #region properties
        
        public string Name
        {
            get { return _Name; }
            set { _Name = ProgNetComponents.Tools.ConstHelper.GetFriendlyName(value); }
        }

        public string Caption
        {
            get;
            set;
        }

        public string Group
        {
            get;
            set;
        }

        [RefreshProperties(RefreshProperties.All)]
        public bool IsStatic
        {
            get;
            set;
        }

        [BrowsableByPropertyValue("IsStatic", false)]
        [Editor("System.ComponentModel.Design.MultilineStringEditor, System.Design, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", typeof(UITypeEditor))]
        public string CustomColumnQuery
        {
            get;
            set;
        }

        [BrowsableByPropertyValue("IsStatic", false)]
        [Editor("System.ComponentModel.Design.MultilineStringEditor, System.Design, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", typeof(UITypeEditor))]
        public string CustomFromQuery
        {
            get;
            set;
        }

        [BrowsableByPropertyValue("IsStatic", false)]
        [Editor("System.ComponentModel.Design.MultilineStringEditor, System.Design, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", typeof(UITypeEditor))]
        public string CustomFilterQuery
        {
            get;
            set;
        }

        [BrowsableByPropertyValue("IsStatic", false)]
        [TypeConverter(typeof(StringArrayTypeConverter))]
        public string[] Tables
        {
            get;
            set;
        }

        [BrowsableByPropertyValue("IsStatic", true)]
        public bool RefreshOnPopup
        {
            get;
            set;
        }

        [RefreshProperties(RefreshProperties.All)]
        public BrowserDisplayType DisplayType
        {
            get;
            set;
        }

        [BrowsableByPropertyValue("DisplayType", BrowserDisplayType.ConfigSpecified)]
        public BrowserConfigDisplayType DefaultConfigDisplayType
        {
            get;
            set;
        }

        [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
        public BrowserColumnCollection Columns
        {
            get
            {
                if (_Columns == null)
                    _Columns = new BrowserColumnCollection();
                return _Columns;
            }
        }
        
        [UIEditor(typeof(BrowserColumnMemberEditor))]
        public string ValueMember
        {
            get;
            set;
        }
        
        [UIEditor(typeof(BrowserColumnMemberEditor))]
        public string DisplayMember
        {
            get;
            set;
        }

        [UIEditor(typeof(BrowserColumnMemberEditor))]
        public string ChildColumn
        {
            get;
            set;
        }

        public string Filter
        {
            get;
            set;
        }

        [Browsable(false)]
        public string DisplayFilter
        {
            get;
            set;
        }
        #endregion

        /// <summary>
        /// Shows dialog. If allowNew New button is wisible
        /// </summary>
        /// <param name="editValue"></param>
        /// <param name="allowNew"></param>
        /// <param name="multiSelect">Multiselect</param>
        /// <returns></returns>
        public ObjectDialogResult ShowDialog(object editValue, bool allowNew, bool multiSelect = false)
        {
            BrowserCache.OnBeforeBrowserShowDialog(this.BrowserId);
            Form.MultiSelect = multiSelect;
            Form.InitForm(this, allowNew, editValue);
            Form.DisplayFilter = DisplayFilter;
            ObjectDialogResult dlg = new ObjectDialogResult();
            dlg.DialogResult = Form.ShowDialog();
            if (dlg.DialogResult == DialogResult.OK)
                dlg.Value = Form.EditValue;
            return dlg;
        }
        /// <summary>
        /// shows dialog without New button
        /// </summary>
        /// <param name="editValue"></param>
        /// <returns></returns>
        public ObjectDialogResult ShowDialog(object editValue)
        {
            return ShowDialog(editValue, false);
        }
        /// <summary>
        /// shows dialog without New button
        /// </summary>
        /// <returns></returns>
        public ObjectDialogResult ShowDialog()
        {
            return ShowDialog(null);
        }
        /// <summary>
        /// Shows dialog with New button
        /// </summary>
        /// <param name="editValue"></param>
        /// <returns></returns>
        public ObjectDialogResult ShowNewDialog(object editValue)
        {
            return ShowDialog(editValue, true);
        }
        public ObjectDialogResult ShowNewDialog()
        {
            return ShowDialog(null, true);
        }
        /// <summary>
        /// shows dialog without New button
        /// </summary>
        /// <param name="editValue"></param>
        /// <returns></returns>
        public ObjectDialogResult ShowMultiSelectDialog(object editValue)
        {
            return ShowDialog(editValue, false, true);
        }
        /// <summary>
        /// shows dialog without New button
        /// </summary>
        /// <returns></returns>
        public ObjectDialogResult ShowMultiSelectDialog()
        {
            return ShowMultiSelectDialog(null);
        }

        public DataTable GetTable()
        {
            return BrowserCache.GetBrowserData(BrowserId);
        }
        public DataView GetDataView()
        {
            DataView dv = new DataView(GetTable());
            dv.RowFilter = DisplayFilter;
            return dv;
        }

        /// <summary>
        /// Returns row for specified Value
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        public DataRow GetRowForValue(object value)
        {
            return BrowserCache.GetRowForValue(BrowserId, value, DisplayFilter);
        }
        /// <summary>
        /// Check if Browser has Row with DisplayMember = value
        /// </summary>
        /// <param name="nullIsValid"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        public bool IsValidDisplayMember(bool nullIsValid, object value)
        {
            return BrowserCache.IsValidDisplayMember(this.BrowserId, nullIsValid, value, DisplayFilter);
        }
        /// <summary>
        /// Gets value from DisplayMember column for specified value
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        public object GetDisplayForValue(object value)
        {
            return BrowserCache.GetDisplayForValue(this.BrowserId, value, DisplayFilter);
        }

        /// <summary>
        /// Gets value from DisplayMember column for specified values
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        public object GetDisplayForValues(object[] value, string separator)
        {
            return BrowserCache.GetDisplayForValues(this.BrowserId, value, DisplayFilter, separator);
        }

        public object GetColumnValueForEditValue(object value, string column)
        {
            return BrowserCache.GetColumnValueForEditValue(this.BrowserId, value, column, DisplayFilter);
        }
        /// <summary>
        /// Check if Browser has Row for Value. if Value is null returns nullIsValid
        /// </summary>
        /// <param name="nullIsValid"></param>
        ///  /// <param name="value"></param>
        /// <returns></returns>
        public bool IsValid(bool nullIsValid, object value)
        {
            return BrowserCache.IsValid(BrowserId, nullIsValid, value, DisplayFilter);

        }
        /// <summary>
        /// Checks every row if value of column is valid. If not and errorMsg is not null, sets column error
        /// </summary>
        /// <param name="nullIsValid"></param>
        /// <param name="column"></param>
        /// <param name="errorMsg"></param>
        /// <param name="rows"></param>
        /// <returns></returns>
        public bool IsValid(bool nullIsValid, string column, string errorMsg, params DataRow[] rows)
        {
            return BrowserCache.IsValid(BrowserId, nullIsValid, column, errorMsg, DisplayFilter, rows);
        }
        /// <summary>
        /// Checks every row from table (selected for filter) if value of column is valid. If not and errorMsg is not null, sets column error
        /// </summary>
        /// <param name="nullIsValid"></param>
        /// <param name="column"></param>
        /// <param name="errorMsg"></param>
        /// <param name="dt"></param>
        /// <param name="filter"></param>
        /// <returns></returns>
        public bool IsValid(bool nullIsValid, string column, string errorMsg, DataTable dt)
        {
            return BrowserCache.IsValid(BrowserId, nullIsValid, column, errorMsg, dt, DisplayFilter);
        }
       
        [Browsable(false)]
        public object BrowserId
        {
            get;
            set;
        }

        #region ICloneable Members

        public object Clone()
        {
            Browser b = new Browser();
            b.Caption = this.Caption;
            b.DisplayType = this.DisplayType;
            b.DefaultConfigDisplayType = this.DefaultConfigDisplayType;
            b.Group = this.Group;
            b.IsStatic = this.IsStatic;
            b.Name = Name;
            b.Tables = this.Tables;
            b.ValueMember = this.ValueMember;
            b.DisplayMember = this.DisplayMember;
            b.Filter = Filter;
            b.RefreshOnPopup = RefreshOnPopup;
            b.BrowserId = BrowserId;
            b.CustomColumnQuery = CustomColumnQuery;
            b.CustomFilterQuery = CustomFilterQuery;
            b.CustomFromQuery = CustomFromQuery;
            foreach (BrowserColumn c in this.Columns)
                b.Columns.Add(c.Clone() as BrowserColumn);
            return b;
        }

        #endregion
    }

    public class BrowserCollection : ProgNetComponents.Collections.BaseNamedCollection<Browser>
    {

    }

    public abstract class BrowserNames
    {

    } 

    [Designer(typeof(CollectionComponentDesigner))]
    public class BrowserContainer : Component
    {
        internal static IServiceProvider ServiceProvider
        {
            get;
            set;
        }

        private BrowserGroupCollection _Items = new BrowserGroupCollection();
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]

        public BrowserGroupCollection Items
        {
            get { return _Items; }
        }
    }

    [TypeConverter(typeof(BrowserGroupTypeConverter))]
    public class BrowserGroup : BaseNamedObject, INamedGroup
    {
        public BrowserGroup()
        {

        }
        public BrowserGroup(string name)
            : this(name, null, null)
        {

        }
        public BrowserGroup(string name, Browser[] browsers)
            : this(name, null, browsers)
        {
        }
        public BrowserGroup(string name, BrowserGroup[] groups)
            : this(name, groups, null)
        {
        }
        public BrowserGroup(string name, BrowserGroup[] groups, Browser[] browsers)
        {
            Name = name;
            if (groups != null)
                Groups.AddRange(groups);
            if (browsers != null)
                Items.AddRange(browsers);
        }

        BrowserCollection _Items = new BrowserCollection();
        BrowserGroupCollection _Groups = new BrowserGroupCollection();
        
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
        public BrowserCollection Items
        {
            get
            {
                return _Items;
            }
        }
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
        public BrowserGroupCollection Groups
        {
            get { return _Groups; }
        }

        #region INamedGroup Members

        System.Collections.IList INamedGroup.Groups
        {
            get { return _Groups; }
        }

        System.Collections.IList INamedGroup.Items
        {
            get { return _Items; }
        }

        bool INamedGroup.HasAnyItems()
        {
            if (_Items.Count > 0)
                return true;
            foreach (INamedGroup g in _Groups)
                if (g.HasAnyItems())
                    return true;
            return false;
        }

        #endregion

    }
    
    [Editor(typeof(ProgNetComponentsDx.Browsers.Design.BrowserGroupCollectionEditor), typeof(System.Drawing.Design.UITypeEditor))]
    public class BrowserGroupCollection : ProgNetComponents.Collections.BaseNamedCollection<BrowserGroup>
    {

    }
}
